home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / video / fly8111-.000 / fly8111- / fly8 / editstr.c < prev    next >
C/C++ Source or Header  |  1979-12-31  |  12KB  |  545 lines

  1. /* --------------------------------- editstr.c ------------------------------ */
  2.  
  3. /* This is part of the flight simulator 'fly8'.
  4.  * Author: Eyal Lebedinsky (eyal@ise.canberra.edu.au).
  5. */
  6.  
  7. /* User input with editing. This is built around C code from a mag (forget
  8.  * which one) but the original author's note follows.
  9. */
  10.  
  11. /* Get input string, with VMS-style input line editing
  12.  * and previous-command scrolling.
  13.  *
  14.  * Written for Turbo C 2.0 / Borland C++ 2.0
  15.  * Bob Bybee, 2/91
  16. */
  17.  
  18. /* Modified for usual msdos keys,
  19.  * Eyal Lebedinsky, Feb 1992
  20.  *
  21.  * Use microsoft C. Original program compiled and run without any changes
  22.  *   with this compiler.
  23.  * Show insert/overtype mode as cursor size[sys_show].
  24.  * Initial mode is overwrite!
  25.  * User can select length for shortest string kept [shortest_saved].
  26.  * If an earlier line is selected (with up/down arrows) and entered then it
  27.  *   is not saved again.
  28.  * Provide history search with PAGE_UP key: Previous entry that matches up
  29.  *   to the cursor is retrieved.
  30.  * Added keys:
  31.  *   HOME        move to start of line (CTRL-B)
  32.  *   END        move to end   of line (CTRL-E)
  33.  *   ESC        clear line (CTRL-X)
  34.  *   INSERT        toggle mode (CTRL-A)
  35.  * Added keys with new functions:
  36.  *   C_RIGHT_ARROW    move to next word start
  37.  *   C_LEFT_ARROW    move to prev word start
  38.  *   DEL        delete char at right of cursor
  39.  *   C_END        delete right of cursor to end of line
  40.  *   C_HOME        delete left of cursor to start of line
  41.  *   PAGE_UP        search line prefix
  42.  *   Ctrl-Y        Recall original line
  43.  *   Ctrl-Q        Abort
  44. */
  45.  
  46. /* Modified for fly8
  47.  * Eyal Lebedinsky, Nov 1992
  48.  *
  49.  * Removed escape-sequences for input.
  50.  * Removed init function.
  51.  * Modified to use fly8 key names.
  52.  * Modified to interact with fly8 input/output.
  53.  *
  54.  * Eyal Lebedinsky, Aug 1994
  55.  *
  56.  * Split Fly8 stuff from the generic code. However, to simplify things, the
  57.  * keyboard mapping is still shared.
  58. */
  59.  
  60. #include "fly.h"
  61.  
  62.  
  63. /* ASCII key definitions
  64. */
  65. #define ESC_KEY            K_ESC
  66. #define DELETE_KEY        K_DEL
  67. #define BACKSPACE_KEY        K_RUBOUT
  68. #define RETURN_KEY         K_ENTER
  69. #define CTRL(x)            ((x) | K_CTRL)
  70.  
  71. /* Values for tracking cursor key entry
  72. */
  73. #define UP_ARROW    K_UP
  74. #define DOWN_ARROW    K_DOWN
  75. #define RIGHT_ARROW    K_RIGHT
  76. #define LEFT_ARROW    K_LEFT
  77. #define HOME        K_HOME
  78. #define END        K_END
  79. #define INSERT        K_INS
  80. #define C_LEFT_ARROW    (K_LEFT  | K_CTRL)
  81. #define C_RIGHT_ARROW    (K_RIGHT | K_CTRL)
  82. #define C_END        (K_END   | K_CTRL)    
  83. #define C_HOME        (K_HOME  | K_CTRL)    
  84. #define PAGE_UP        K_PGUP    
  85.  
  86. #define RECSUB(x)    (((x) + max_recall) % max_recall)
  87. #define RECALL(i)    recalls[i].s
  88. #define RECLEN(i)    recalls[i].len
  89. #define WSTR        RECALL(max_recall)
  90. #define WLEN        RECLEN(max_recall)
  91.  
  92. struct recall {
  93.     char    *s;
  94.     int    len;
  95. };
  96.  
  97.  
  98. /* These three is all that is needed to define a history queue between
  99.  * calls to editstr().
  100. */
  101. static struct recall    FAR *recalls = 0;
  102. static int        historyptr = 0;    /* ptr to last line entered */
  103. static int        max_recall = 0;
  104. static int        shortest_saved = 0;
  105.  
  106.  
  107. #define INSERT_MODE    0x0001
  108. #define INIT_MODE    INSERT_MODE    /* 1=insert 0=overwrite */
  109.  
  110. static int        num_got = 0;    /* # chars in input buffer */
  111. static int        cursor_pos = 0;    /* cursor position on line */
  112. static int        edit_mode = INIT_MODE;
  113.  
  114.  
  115. /* prototypes for this file
  116. */
  117. LOCAL_FUNC int    NEAR sys_term (void);
  118. LOCAL_FUNC int    NEAR sys_init (void);
  119. LOCAL_FUNC void    NEAR clear_line (void);
  120. LOCAL_FUNC int    NEAR cursor_right (void);
  121. LOCAL_FUNC int    NEAR cursor_left (void);
  122. LOCAL_FUNC int    NEAR get_char_esc (void);
  123. LOCAL_FUNC void    NEAR put_str (char FAR* str);
  124.  
  125. static void *    (FAR *sys_malloc) (int n) = NULL;
  126. static void *    (FAR *sys_free) (void *p, int n) = NULL;
  127. static void    (FAR *sys_put) (int ch) = NULL;
  128. static int    (FAR *sys_get) (void) = NULL;
  129. static void    (FAR *sys_show) (int edit_mode) = NULL;
  130.  
  131. /* Set up the editstr API.
  132. */
  133. extern int FAR
  134. editset (void *    (FAR *s_malloc) (int n),
  135.     void *    (FAR *s_free) (void *p, int n),
  136.     void    (FAR *s_put) (int ch),
  137.     int    (FAR *s_get) (void),
  138.     void    (FAR *s_show) (int edit_mode),
  139.     int    s_saved,
  140.     int    m_recall)
  141. {
  142.     sys_malloc = s_malloc;
  143.     sys_free   = s_free;
  144.     sys_put    = s_put;
  145.     sys_get    = s_get;
  146.     sys_show   = s_show;
  147.     shortest_saved = s_saved;
  148.     if (m_recall)
  149.         max_recall = m_recall;
  150.  
  151.     return (0);
  152. }
  153.  
  154. /* Get edit status.
  155. */
  156. extern int FAR
  157. editget (char **str, int *len, int *pos, int *mode)
  158. {
  159.     *str = WSTR;
  160.     *len = num_got;
  161.     *pos = cursor_pos;
  162.     *mode = edit_mode & INSERT_MODE;
  163.     return (0);
  164. }
  165.  
  166. /* Do termination processing.
  167. */
  168. LOCAL_FUNC int NEAR
  169. sys_term (void)
  170. {
  171.     int    i;
  172.  
  173.     if (NULL == recalls)
  174.         return (0);
  175.  
  176.     for (i = 0; i < (int)max_recall; ++i) {
  177.         if (NULL != RECALL(i)) {
  178.             RECALL(i) = (*sys_free) (RECALL(i), RECLEN(i));
  179.             RECLEN(i) = 0;
  180.         }
  181.     }
  182.  
  183.     recalls = (*sys_free) (recalls, (max_recall+1) * sizeof (*recalls));
  184.  
  185.     return (0);
  186. }
  187.  
  188. /* Do initial processing.
  189. */
  190. LOCAL_FUNC int NEAR
  191. sys_init (void)
  192. {
  193.     int    i;
  194.  
  195.     if (NULL != recalls)
  196.         return (0);
  197.  
  198.     recalls = (struct recall *) (*sys_malloc) ((max_recall+1)
  199.                         * sizeof (*recalls));
  200.     if (NULL == recalls)
  201.         return (1);
  202.  
  203.     for (i = 0; i <= (int)max_recall; ++i) {
  204.         RECALL(i) = NULL;
  205.         RECLEN(i) = 0;
  206.     }
  207.  
  208.     return (0);
  209. }
  210.  
  211. /* Erase all characters on the current line.
  212. */
  213. LOCAL_FUNC void NEAR
  214. clear_line (void)
  215. {
  216.     int    i;
  217.  
  218.     while (cursor_left())        /* move to begining of line */
  219.         ;
  220.  
  221.     for (i = 0; i < num_got; ++i)
  222.         (*sys_put)(' ');
  223.     for (i = 0; i < num_got; ++i)
  224.         (*sys_put)('\b');
  225.     cursor_pos = num_got = 0;
  226. }
  227.  
  228. /* Move the cursor right one position, by echoing the
  229.  * character it's currently over.
  230.  * Return 1-OK, 0-can't move.
  231. */
  232. LOCAL_FUNC int NEAR
  233. cursor_right (void)
  234. {
  235.     if (cursor_pos < num_got) {
  236.         (*sys_put)(WSTR[cursor_pos]);
  237.         ++cursor_pos;
  238.         return (1);
  239.     }
  240.     return (0);
  241. }
  242.  
  243. /* Move the cursor left one position, by echoing
  244.  * a backspace.  Return 1-OK, 0-can't move.
  245. */
  246. LOCAL_FUNC int NEAR
  247. cursor_left (void)
  248. {
  249.     if (cursor_pos > 0) {
  250.         (*sys_put)('\b');
  251.         --cursor_pos;
  252.         return (1);
  253.     }
  254.     return (0);
  255. }
  256.  
  257. /* Get a character, with escape processing.
  258.  * Handles special sequences like "ESC [ A" for up-arrow.
  259.  * This function would need to be modified to handle
  260.  * keyboards that are neither PC's nor VT-100's.
  261. */
  262. LOCAL_FUNC int NEAR
  263. get_char_esc (void)
  264. {
  265.     int    ch;
  266.  
  267.     ch = (*sys_get)();
  268.     if (ch != ESC_KEY)
  269.         return (ch);
  270.  
  271.     return (ch);    /* no escapes! */
  272. }
  273.  
  274. /* Put a string to (*sys_put)().
  275. */
  276. LOCAL_FUNC void NEAR
  277. put_str (char FAR* s)
  278. {
  279.     while (*s != '\0')
  280.         (*sys_put)(*s++);
  281. }
  282.  
  283.  
  284. /* editstr() is called to get a line of input.
  285.  * The input line is placed in "str" and will be no
  286.  * more than "len" characters.
  287. */
  288. extern int FAR
  289. editstr (char FAR *str, int len)
  290. {
  291.     int    i, c;
  292.     int    curptr;            /* current visible entry */
  293.     int    GoOn;
  294.  
  295.     if (NULL == str && 0 == len)
  296.         return (sys_term ());
  297.     if (!recalls) {
  298.         if (sys_init ())
  299.             return (-1);
  300.     }
  301.  
  302.     if (len < 1)
  303.         return (-2);
  304.  
  305.     (*sys_show) (edit_mode = INIT_MODE);
  306.     cursor_pos = 0;
  307.     curptr = historyptr;
  308.  
  309.     WSTR = (char *) (*sys_malloc) (len);
  310.     if (NULL == WSTR)
  311.         return (-3);
  312.     WLEN = len;
  313.     strcpy (WSTR, str);            /* keep it */
  314.  
  315.     put_str (WSTR);
  316.     cursor_pos = num_got = strlen (WSTR);
  317.  
  318.     for (GoOn = 1; GoOn;) {
  319.         switch (c = get_char_esc()) {
  320.         case RETURN_KEY:        /* done */
  321.             GoOn = 0;
  322.             break;
  323.         case CTRL('q'):            /* abort */
  324.             clear_line();
  325.             return (1);
  326.         case DELETE_KEY:        /* del char on right */
  327.         case BACKSPACE_KEY:        /* del char on left */
  328.             if ((c == DELETE_KEY && cursor_pos < num_got) ||
  329.                 (c != DELETE_KEY && cursor_left())) {
  330.                 ++cursor_pos;
  331.                 for (i = cursor_pos; i < num_got; ++i) {
  332.                     WSTR[i - 1] = WSTR[i];
  333.                     (*sys_put)(WSTR[i]);
  334.                 }
  335.                 (*sys_put)(' ');
  336.                 for (i = cursor_pos; i <= num_got; ++i)
  337.                     (*sys_put)('\b');
  338.                 --num_got;
  339.                 --cursor_pos;
  340.             }
  341.             break;
  342.         case C_END:            /* erase to end-of-line */
  343.             if (cursor_pos < num_got) {
  344.                 for (i = cursor_pos; i < num_got; ++i) {
  345.                     WSTR[i] = ' ';
  346.                     (*sys_put)(' ');
  347.                 }
  348.                 for (i = cursor_pos; i < num_got; ++i)
  349.                     (*sys_put)('\b');
  350.                 num_got = cursor_pos;
  351.             }
  352.             break;
  353.         case C_HOME:            /* erase to beg-of-line */
  354.             if (cursor_pos > 0) {
  355.                 for (i = 0; i < cursor_pos; ++i)
  356.                     (*sys_put)('\b');
  357.                 num_got -= cursor_pos;
  358.                 for (i = 0; i < num_got; ++i) {
  359.                     WSTR[i] = WSTR[cursor_pos+i];
  360.                     (*sys_put)(WSTR[i]);
  361.                 }
  362.                 for (i = 0; i < cursor_pos; ++i)
  363.                     (*sys_put)(' ');
  364.                 for (i = cursor_pos + num_got; i-- > 0;)
  365.                     (*sys_put)('\b');
  366.                 cursor_pos = 0;
  367.             }
  368.             break;
  369.         case CTRL('x') :        /* erase all line */
  370.         case ESC_KEY:
  371.             clear_line();
  372.             break;
  373.         case CTRL('a'):            /* insert/overtype */
  374.         case INSERT:
  375.             (*sys_show) (edit_mode ^= INSERT_MODE);
  376.             break;
  377.         case CTRL('b'):            /* cursor to beg-of-line */
  378.         case HOME:
  379.             while (cursor_left())
  380.                 ;
  381.             break;
  382.         case CTRL('e'):            /* cursor to end-of-line */
  383.         case END:
  384.             while (cursor_right())
  385.                 ;
  386.             break;
  387.         case CTRL('r'):            /* recall current line */
  388.             i = curptr;
  389.             goto recall;
  390.         case CTRL('y'):            /* recall original line */
  391.             strncpy (WSTR, str, len);
  392.             curptr = historyptr;
  393.             goto reshow;
  394.         case UP_ARROW:            /* recall prev line */
  395.             for (i = curptr; (i = RECSUB(i-1)) != curptr;) {
  396.                 if (NULL != RECALL(i))
  397.                     goto recall;
  398.             }
  399.             break;
  400.         case DOWN_ARROW:        /* recall next line */
  401.             for (i = curptr; (i = RECSUB(i+1)) != curptr;) {
  402.                 if (NULL != RECALL(i))
  403.                     goto recall;
  404.             }
  405.             break;
  406.         case PAGE_UP:            /* find by prefix */
  407.             for (i = curptr; (i = RECSUB(i-1)) != curptr;) {
  408.                 if (!memcmp (WSTR, RECALL(i), cursor_pos))
  409.                     goto recall;
  410.             }
  411.             (*sys_put) ('\a');
  412.             break;
  413.         recall:
  414.             strncpy (WSTR, RECALL(i), len);
  415.             curptr = i;
  416.         reshow:
  417.             c = cursor_pos;
  418.             clear_line();
  419.             put_str (WSTR);
  420.             cursor_pos = num_got = strlen (WSTR);
  421.             while (cursor_pos > c)
  422.                 cursor_left ();
  423.             break;
  424.         case LEFT_ARROW:        /* cursor left */
  425.             if (cursor_pos > 0) {
  426.                 (*sys_put)('\b');
  427.                 --cursor_pos;
  428.             }
  429.             break;
  430.         case RIGHT_ARROW:        /* cursor right */
  431.             cursor_right();
  432.             break;
  433.         case C_LEFT_ARROW:        /* find left space */
  434.             while (cursor_pos > 0 && WSTR[cursor_pos-1] == ' ') {
  435.                 (*sys_put)('\b');
  436.                 --cursor_pos;
  437.             }
  438.             while (cursor_pos > 0 && WSTR[cursor_pos-1] != ' ') {
  439.                 (*sys_put)('\b');
  440.                 --cursor_pos;
  441.             }
  442.             break;
  443.         case C_RIGHT_ARROW:        /* find right space */
  444.             while (cursor_pos < num_got && WSTR[cursor_pos] != ' ')
  445.                 cursor_right();
  446.             while (cursor_pos < num_got && WSTR[cursor_pos] == ' ')
  447.                 cursor_right();
  448.             break;
  449.         default:
  450.             if (' ' <= c && c < 0x7f) {
  451.                 if (edit_mode & INSERT_MODE) {
  452.                 if (num_got < len - 1) {
  453. /* Move right, all the characters
  454.  * to the right of cursor_pos.
  455. */
  456.                     for (i = num_got; i > cursor_pos; --i)
  457.                         WSTR[i] = WSTR[i - 1];
  458.                     WSTR[cursor_pos] = (char)c;
  459.                     for (i = cursor_pos; i <= num_got; ++i)
  460.                         (*sys_put)(WSTR[i]);
  461.                     for (i = cursor_pos; i < num_got; ++i)
  462.                         (*sys_put)('\b');
  463.                     ++num_got;
  464.                     ++cursor_pos;
  465.                 }
  466.                 } else {
  467.                 if (cursor_pos < len - 1) {
  468.                     WSTR[cursor_pos] = (char)c;
  469.                     (*sys_put)(c);
  470.                     if (cursor_pos == num_got)
  471.                         ++num_got;
  472.                     ++cursor_pos;
  473.                 }
  474.                 }
  475.             }
  476.             break;
  477.         } /* switch */
  478.     } /* for */
  479.  
  480.     WSTR[num_got] = '\0';
  481.     (*sys_put)('\n');
  482.  
  483.     strcpy (str, WSTR);        /* copy to user space */
  484.  
  485. /* If this line is non-empty, and different
  486.  * from the last one accepted, store it into
  487.  * the recall buffer.
  488. */
  489.  
  490.     if (num_got < shortest_saved)
  491.         i = 0;        /* too short */
  492.     else if (RECALL(curptr) && !strcmp (WSTR, RECALL(curptr)))
  493.         i = 0;        /* same as current */
  494.     else if (RECALL(historyptr) && !strcmp (WSTR, RECALL(historyptr)))
  495.         i = 0;        /* same as prev */
  496.     else
  497.         i = 1;
  498.     if (i) {
  499.         historyptr = RECSUB(historyptr + 1);
  500.  
  501.         if (RECALL(historyptr)) {
  502.             RECALL(historyptr) = (*sys_free) (RECALL(historyptr),
  503.                             RECLEN(historyptr));
  504.             RECLEN(historyptr) = 0;
  505.         }
  506.  
  507.         len = strlen (WSTR) + 1;
  508.         RECALL(historyptr) = (char *) (*sys_malloc) (len);
  509.         if (NULL != RECALL(historyptr)) {
  510.             RECLEN(historyptr) = len;
  511.             strcpy (RECALL(historyptr), WSTR);
  512.         }
  513.     }
  514.  
  515.     WSTR = (*sys_free) (WSTR, WLEN);
  516.     WLEN = 0;
  517.  
  518.     return (0);
  519. }
  520.  
  521. #undef ESC_KEY
  522. #undef DELETE_KEY
  523. #undef BACKSPACE_KEY
  524. #undef RETURN_KEY
  525. #undef CTRL
  526. #undef UP_ARROW
  527. #undef DOWN_ARROW
  528. #undef RIGHT_ARROW
  529. #undef LEFT_ARROW
  530. #undef HOME
  531. #undef END
  532. #undef INSERT
  533. #undef C_LEFT_ARROW
  534. #undef C_RIGHT_ARROW
  535. #undef C_END
  536. #undef C_HOME
  537. #undef PAGE_UP
  538. #undef RECSUB
  539. #undef RECALL
  540. #undef RECLEN
  541. #undef WSTR
  542. #undef WLEN
  543. #undef INSERT_MODE
  544. #undef INIT_MODE
  545.